package edu.columbia.aicheckers.model;

import java.util.HashSet;
import java.util.Set;

/**
 * Contains many common methods for checking on status and enacting
 * certain commands present in the checker ruleset
 * @author C.M.R.
 *
 */
public class CheckersUtil {

	static HashSet<Move> moves = new HashSet<Move>();
	
	public static boolean isValidMove(IBoardState state,Move move)
	{
		moves.clear();
		if(move.getCheckerPiece() == null || move.getCheckerPiece().getColor() != state.getCurrentPly())
		{
			return false;
		}
		Set<Move> allAvailableMoves = state.getAvailableMoves(state.getCurrentPly());
		return allAvailableMoves.contains(move);
		
	}
	
	/**
	 * Checks to see if a skip is possible among the next possible moves
	 * @param moves
	 * @return
	 */
	public static boolean containsSkip(Set<Move> moves) 
	{
		for(Move m : moves)
		{
			if(m.hasSkip())
			{
				return true;
			}
		}
		return false;
	}

	/**
	 * Returns the next available moves
	 * @param state
	 * @param checker
	 * @param moveList
	 */
	public static void getNextAvailableMoves(IBoardState state, Checker checker, Set<Move> moveList)
	{
		int location = checker.getLocation();
		if(state.getChecker(location) == checker && checker.getColor() == state.getCurrentPly())
		{
			if(!checker.isKing())
			{
				// Check if piece is white or black
				if(checker.getColor() == Color.White)
				{
					getMovesWhite(state,checker,moveList);
					return;
				}
				else
				{
					getMovesBlack(state,checker,moveList);
					return;
				}
			}
			else
			{
				getMovesWhite(state,checker,moveList);
				getMovesBlack(state,checker,moveList);
				return;
			}
		}
		else
		{
			if(checker.getColor() != state.getCurrentPly())
			{
				throw new IllegalArgumentException("Checker is not allowed to move at the current state - it's not the turn of " + checker.getColor());
			}
			throw new IllegalArgumentException("Checker piece does not belong on this board - or location is bad");
		}
		
	}
	
	private static HashSet<Move> skipMoves = new HashSet<Move>();
	
	static void processManadatorySkipMoves(Set<Move> moveList)
	{
		boolean hasSkipMove = false;
		skipMoves.clear();
		for(Move m : moveList)
		{
			if(m.hasSkip())
			{
				hasSkipMove = true;

				skipMoves.add(m);
			}
			
		}
		
		if(hasSkipMove)
		{
			moveList.clear();
			moveList.addAll(skipMoves);
		}
	}
	
	
	private static void getMovesWhite(IBoardState state, Checker checker, Set<Move> moveSet)	
	{
		int location = checker.getLocation();
		boolean upBoard = true;
		switch(location % 8)
		{
			case 0:
				if(location == 8)
				{
					goLeftOne(state, checker, moveSet,upBoard);
					goRightOne(state, checker, moveSet,upBoard);
					break;
				}
				else
				{
					goRightOne(state, checker, moveSet,upBoard);
					goLeftOne(state, checker, moveSet,upBoard);
					goLeftTwo(state, checker, moveSet,upBoard);
				}
				break;
			case 1:
				if(location == 1)
				{
					if(!checker.isKing())
						throw new IllegalArgumentException("Checker should be a king checker:" + checker);
				}
				else
				{
					goLeftOne(state, checker, moveSet, upBoard);
					goRightOne(state, checker, moveSet, upBoard);
					goRightTwo(state, checker, moveSet, upBoard);
				}
				break;
			case 2:
			case 3:
				if(location < 8)
				{
					if(!checker.isKing)
						throw new IllegalArgumentException("Checker should be a king checker:" + checker);
				}
				else
				{
					goRightOne(state, checker, moveSet, upBoard);
					goRightTwo(state, checker, moveSet, upBoard);
				    goLeftOne(state, checker, moveSet, upBoard);
				    goLeftTwo(state, checker, moveSet, upBoard);
				}
				break;
			case 4:
				if(location == 4)
				{
					if(!checker.isKing())
						throw new IllegalArgumentException("Checker should be a king checker: " + checker);
				}
				else
				{
					goLeftOne(state, checker, moveSet, upBoard);
					goLeftTwo(state, checker, moveSet, upBoard);
				}
				break;
			case 5:
				if(location == 5)
				{
					goRightOne(state, checker, moveSet,upBoard);
				}
				else
				{
					goRightOne(state, checker, moveSet,upBoard);
					goRightTwo(state, checker, moveSet,upBoard);
				}
				break;
			case 6:
				if(location == 6)
				{
					goLeftOne(state, checker, moveSet,upBoard);
					goRightOne(state, checker, moveSet,upBoard);
					break;
				}
				// Fall through
			case 7:
				if(location == 7)
				{
					goLeftOne(state, checker, moveSet,upBoard);
					goRightOne(state, checker, moveSet,upBoard);
					break;
				}
				goRightOne(state, checker, moveSet,upBoard);
				goRightTwo(state, checker, moveSet,upBoard);
				goLeftOne(state, checker, moveSet,upBoard);
				goLeftTwo(state, checker, moveSet,upBoard);
				break;
				
		}
	}
	
	private static int positionChange(Checker checker,int location, int position, boolean upBoard)
	{
		if(upBoard)
		{
			return location - position;
		}
		else 
		{
			return location + position;
		}
	}
	
	private static void goLeftOne(IBoardState state, Checker checker, Set<Move> moveSet, boolean upBoard)
	{
		int location = checker.getLocation();
		int destination;
		if( (location % 8 <= 4 && location % 8 > 0 && upBoard) ||
				((location % 8 > 4 || location % 8 ==0) && !upBoard)	)
		{
			destination = positionChange(checker,location,4,upBoard);
		}
		else
		{
			destination = positionChange(checker,location,5,upBoard);
		}
		
		if(state.isEmpty(destination))
		{
			moveSet.add(new Move(checker,destination));
		}
	}
	
	private static void goLeftTwo(IBoardState state, Checker checker, Set<Move> moveSet, boolean upBoard)
	{
		int location = checker.getLocation();
		int destination, skipped;
		if( (location % 8 <= 4 && location % 8 > 0 && upBoard) ||
				((location % 8 > 4 || location % 8 ==0) && !upBoard)	)
		{
			skipped = positionChange(checker,location,4,upBoard);
			destination = positionChange(checker,location,9,upBoard);
		}
		else
		{
			skipped = positionChange(checker,location,5,upBoard);
			destination = positionChange(checker,location,9,upBoard);
		}
		
		if(state.isEmpty(destination) && state.isOpponentColor(skipped,checker))
		{
			moveSet.add(new Move(checker,destination,state.getChecker(skipped)));
		}
	}
	
	
	
	private static void goRightOne(IBoardState state, Checker checker, Set<Move> moveSet, boolean upBoard)
	{
		int location = checker.getLocation();
		int destination;
		if( (location % 8 <= 4 && location % 8 > 0 && upBoard) ||
				((location % 8 > 4 || location % 8 ==0) && !upBoard)	)
		{
			destination = positionChange(checker,location,3,upBoard);
		}
		else
		{
			destination = positionChange(checker,location,4,upBoard);
		}
		
		if(state.isEmpty(destination))
		{
			moveSet.add(new Move(checker,destination));
		}
	}
	
	private static void goRightTwo(IBoardState state, Checker checker, Set<Move> moveSet, boolean upBoard)
	{
		int location = checker.getLocation();
		int destination, skipped;
		
		if( (location % 8 <= 4 && location % 8 > 0 && upBoard) ||
				((location % 8 > 4 || location % 8 ==0) && !upBoard)	)
		{
			skipped = positionChange(checker,location,3,upBoard);
			destination = positionChange(checker,location,7,upBoard);
		}
		else
		{
			skipped = positionChange(checker,location,4,upBoard);
			destination = positionChange(checker,location,7,upBoard);
		}
		
		if(state.isEmpty(destination) && state.isOpponentColor(skipped,checker))
		{
			moveSet.add(new Move(checker,destination,state.getChecker(skipped)));
		}
	}
	
	private static void getMovesBlack(IBoardState state, Checker checker, Set<Move> moveSet)
	{
		int location = checker.getLocation();
		boolean upBoard = false;
		switch(location % 8)
		{
			case 1:
				if(location == 25)
				{
					goLeftOne(state, checker, moveSet,upBoard);
					goRightOne(state, checker, moveSet,upBoard);
					break;
				}
				else
				{
					goRightOne(state, checker, moveSet,upBoard);
					goLeftOne(state, checker, moveSet,upBoard);
					goLeftTwo(state, checker, moveSet,upBoard);
				}
				break;
			case 0:
				if(location == 32)
				{
					if(!checker.isKing())
						throw new IllegalArgumentException("Checker should be a king checker:" + checker);
				}
				else
				{
					goLeftOne(state, checker, moveSet,upBoard);
					goRightOne(state, checker, moveSet,upBoard);
					goRightTwo(state, checker, moveSet,upBoard);
				}
				break;
			case 6:
			case 7:
				if(location >= 30)
				{
					if(!checker.isKing())
						throw new IllegalArgumentException("Checker should be a king checker:" + checker);
				}
				else
				{
					goRightOne(state, checker, moveSet,upBoard);
					goRightTwo(state, checker, moveSet,upBoard);
					goLeftOne(state, checker, moveSet,upBoard);
					goLeftTwo(state, checker, moveSet,upBoard);
				}
				break;
			case 5:
				if(location == 29)
				{
					if(!checker.isKing())
						throw new IllegalArgumentException("Checker should be a king checker: " + checker);
				}
				else
				{
					goLeftOne(state, checker, moveSet,upBoard);
					goLeftTwo(state, checker, moveSet,upBoard);
				}
				break;
			case 4:
				if(location == 28)
				{
					goRightOne(state, checker, moveSet,upBoard);
				}
				else
				{
					goRightOne(state, checker, moveSet,upBoard);
					goRightTwo(state, checker, moveSet,upBoard);
				}
				break;
			case 3:
				if(location == 27)
				{
					goLeftOne(state, checker, moveSet,upBoard);
					goRightOne(state, checker, moveSet,upBoard);
					break;
				}
				// Fall through
			case 2:
				if(location == 26)
				{
					goLeftOne(state, checker, moveSet,upBoard);
					goRightOne(state, checker, moveSet,upBoard);
					break;
				}
				goRightOne(state, checker, moveSet,upBoard);
				goRightTwo(state, checker, moveSet,upBoard);
				goLeftOne(state, checker, moveSet,upBoard);
				goLeftTwo(state, checker, moveSet,upBoard);
				break;
				
		}
	}
}
